/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frmodule_mng.c                                     */
/*  NOTE      = 模块管理                                           */
/*  DATE      = 2014/10/29                                         */
/*******************************************************************/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <dlfcn.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frstr.h"
#include "frconfig.h"
#include "conntrack.h"
#include "frame_params.h"
#include "frame.h"
#include "module.h"
#include "frmodule_stub.h"
#include "frmodule_mng.h"

/* 协议解析库路径 */
#define APM_ANALYZER_LIB_INFO_NEW    "module_info_new"
/* 协议解析库最小内存大小 (10M) */
#define APM_ANALYZER_LIB_MEMPOOL_MIN    10485100

//多长时间检查数据1次(sec)
#define APM_MNG_MODULE_CHK_TIME    2

typedef struct __st_chk_module {
    Frlist_header *p_lst_hdr;
    int i_ip_proto;
    int i_is_autocheck;
} Frchk_module_mng;

static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
static Frlist_header *g_p_st_hdr_mng_module_use=NULL;//当前使用模块
static Frlist_header *g_p_st_hdr_mng_module_del=NULL;//需要删除的模块
static pthread_t g_thread_id_chk=0;

static void __frmodule_free_l7_module(L7_module *p_st_l7_module_dst);


/*******************************************************************************
*  FUNC     :  节点内容出力
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_outbuff       (出力内容指针)
            :  ui_buff_size    (出力内容空间)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
void frmodule_mng_list_node_mng_show(Frlist_node* p_st_node, char *p_outbuff, unsigned int ui_buff_size)
{
    Frmodule_mng *p_st_module_mng = NULL;
    L7_module *p_st_l7_module=NULL;
    
    if(p_st_node==NULL || p_st_node->data == NULL || ui_buff_size <= 0 )
        return;

    p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    p_st_l7_module = &p_st_module_mng->st_l7_module;
    
    snprintf(p_outbuff, ui_buff_size, "\tl7_proto=%d\tmodule_name=%s %s(handle=%p)\tip_proto=%s(%d) stub=%s autocheck=%s [%s]\n"
           , p_st_l7_module->i_l7_proto
           , p_st_l7_module->p_module_name , p_st_l7_module->p_version, p_st_module_mng->p_so_handle
           , FR_L4PROTO2STR(p_st_l7_module->us_l4_proto), p_st_l7_module->us_l4_proto
           , FR_YESNO2STR(p_st_module_mng->i_is_stub)
           , FR_YESNO2STR(p_st_module_mng->i_is_autocheck)
           , p_st_module_mng->p_so_name
           );
    return;
}


/*******************************************************************************
*  FUNC     :  管理节点内存释放
*  ARGS     :  p_st_node  (Frlist_node *)
*  RTN      :
*  NOTE     : 
*******************************************************************************/
static void __list_node_mng_free(Frlist_node *p_st_node)
{
    Frmodule_mng *p_st_module_mng = NULL;
    
    if(p_st_node==NULL || p_st_node->data == NULL )
        return;

    //获取节点下的管理模块
    p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    FRLOG_INFO_DETAIL("unload %s[%s]", p_st_module_mng->st_l7_module.p_module_name, p_st_module_mng->p_so_name);

    __frmodule_free_l7_module(&p_st_module_mng->st_l7_module);

    //释放管理模块信息
    if(p_st_module_mng->p_so_handle)
    {
        frdbg("p_so_handle=%p\t[%s]\n", p_st_module_mng->p_so_handle, p_st_module_mng->p_so_name);

        dlclose(p_st_module_mng->p_so_handle);
        p_st_module_mng->p_so_handle = NULL;
    }

    if(p_st_module_mng->p_so_name)
        frfree(p_st_module_mng->p_so_name);

    frfree(p_st_module_mng);
    return;
}

/*******************************************************************************
*  FUNC     :  按l7协议查找函数
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_compare_data  (比较用数据)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
static int __list_node_mng_find_l7_proto(Frlist_node *p_st_node, const void *p_compare_data)
{
    Frmodule_mng *p_st_module_mng;
    L7_module *p_st_l7_module;
    if(!p_compare_data)
        return 1;
    
    p_st_l7_module = (L7_module *)p_compare_data;
    p_st_module_mng = (Frmodule_mng*)FRLIST_GET_NODE_DATA(p_st_node);
    
    if(p_st_module_mng == NULL)
        return 1;
    
    if(p_st_module_mng->st_l7_module.i_l7_proto == p_st_l7_module->i_l7_proto )
        return 0;
    return 1;
}


/*******************************************************************************
*  FUNC     :  按handle查找函数
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_compare_data  (比较用数据)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
static int __list_node_mng_find_handle(Frlist_node *p_st_node, const void *p_compare_data)
{
    Frmodule_mng *p_st_module_mng;
    if(!p_compare_data)
        return 1;
    
    p_st_module_mng = (Frmodule_mng*)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_module_mng && p_st_module_mng->p_so_handle == p_compare_data )
        return 0;
    return 1;
}

/*******************************************************************************
*  FUNC     :  模块节点生成
*  ARGS     :  
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  
*******************************************************************************/
static int __frmodule_chk_l7_module(L7_module *p_st_l7_module)
{
    if(p_st_l7_module==NULL)
        return FR_FAIL;
        
    if( (p_st_l7_module->us_l4_proto & IPPROTO_TCP) ==0 && (p_st_l7_module->us_l4_proto & IPPROTO_UDP) == 0 )
        return FR_FAIL;
    
    if(p_st_l7_module->p_version==NULL)
        return FR_FAIL;
    
    if(p_st_l7_module->init==NULL
        || p_st_l7_module->destroy==NULL
        || p_st_l7_module->l7_is==NULL
        || p_st_l7_module->l7_analyze==NULL
        || p_st_l7_module->session_destory==NULL
        )
        return FR_FAIL;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  l7协议模块clone
*  ARGS     :  
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  
*******************************************************************************/
static int __frmodule_clone_l7_module(L7_module *p_st_l7_module_dst, L7_module *p_st_l7_module_src)
{
    if(p_st_l7_module_dst == NULL || p_st_l7_module_src == NULL)
        return FR_FAIL;
    
    memcpy(p_st_l7_module_dst, p_st_l7_module_src, sizeof(L7_module));
    p_st_l7_module_dst->p_module_name = frstrdup(p_st_l7_module_src->p_module_name);
    p_st_l7_module_dst->p_version = frstrdup(p_st_l7_module_src->p_version);
    
    //frdbg("[%s] destroy=%p \n", p_st_l7_module_dst->p_module_name, p_st_l7_module_dst->destroy);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  l7协议模块释放
*  ARGS     :  
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  
*******************************************************************************/
static void __frmodule_free_l7_module(L7_module *p_st_l7_module_dst)
{
    if(p_st_l7_module_dst == NULL )
        return ;

    if(p_st_l7_module_dst->p_module_name)
    {
        frfree(p_st_l7_module_dst->p_module_name);
        p_st_l7_module_dst->p_module_name = NULL;
    }
    if(p_st_l7_module_dst->p_version)
    {
        frfree(p_st_l7_module_dst->p_version);
        p_st_l7_module_dst->p_version = NULL;
    }
    
    if(p_st_l7_module_dst->destroy)
    {
        p_st_l7_module_dst->destroy();
        p_st_l7_module_dst->destroy = NULL;
    }

    return ;
}

#if defined(FRDBG_MODULE_DEBUG)
#include "frmodule_mng.c_dbg"
#endif

/*******************************************************************************
*  FUNC     :  模块so注册
*  ARGS     :  
*  RTN      :  0:成功;1:失败;2:相同so已经加载
*  NOTE     :  1.第1次加载时，默认该模块可以进行协议判断
*           :  2.更新模块时,加载当前so,卸载老so
*           :    (协议解析部分要注意释放老so使用的内存)
*******************************************************************************/
#if !defined(FRDBG_MODULE_DEBUG)
int frmodule_register(const char *p_so_name
                    , int i_is_autocheck
                    , u_short ip_proto
                    , int i_l7_proto
                    , const char *p_module_name
                    , unsigned int ui_mempool_max)
{
    void  *p_so_handle=NULL, *p_so_handle_old=NULL;
    int   (*p_so_fun)();
    Frmodule_mng *p_st_module_mng = NULL;
    L7_module st_l7_module_tmp, st_l7_module_old;
    Frlist_node *p_st_node=NULL;
    int i_ret_fun=0, i_ret = 1;
    int i_is_stub = FR_NO;

    if(g_p_st_hdr_mng_module_use == NULL || p_so_name == NULL)
        return 1;
    
    memset(&st_l7_module_tmp, '\0', sizeof(L7_module));
    //加载so
    p_so_handle=dlopen(p_so_name, RTLD_LAZY); 
    if(p_so_handle == NULL)
    {
        FRLOG_WARN_DETAIL("load [%s] err", dlerror());
        return 1;
    }
    frdbg("p_so_handle=%p\t[%s]\n", p_so_handle, p_so_name);

    //确认同一模块(so)重复注册
    pthread_rwlock_rdlock(&rwlock);
    p_st_node = frlist_find(g_p_st_hdr_mng_module_use, p_so_handle, __list_node_mng_find_handle);
    pthread_rwlock_unlock(&rwlock);
    if(p_st_node)
    {
        dlclose(p_so_handle);
        FRLOG_WARN_DETAIL("the [%s] has loaded", p_so_name);
        return 2;
    }

    //运行模块初始化函数
    p_so_fun   = dlsym( p_so_handle, APM_ANALYZER_LIB_INFO_NEW);
    if(p_so_fun == NULL)
    {
        dlclose(p_so_handle);
        FRLOG_WARN_DETAIL("load [%s][%s] err", p_so_name, APM_ANALYZER_LIB_INFO_NEW);
        return 1;
    }
    
    i_ret_fun = (*p_so_fun)( &st_l7_module_tmp );
    if(i_ret_fun != 0)
    {
        dlclose(p_so_handle);
        FRLOG_WARN_DETAIL("run [%s][%s] err", p_so_name, APM_ANALYZER_LIB_INFO_NEW);
        return 1;
    }
    
    if(st_l7_module_tmp.p_module_name)
        frfree(st_l7_module_tmp.p_module_name);
    st_l7_module_tmp.p_module_name = (char *)p_module_name;
    st_l7_module_tmp.us_l4_proto = ip_proto;
    st_l7_module_tmp.i_l7_proto =i_l7_proto;

    //检查st_l7_module参数是否正确
    i_ret_fun = __frmodule_chk_l7_module(&st_l7_module_tmp);
    if(i_ret_fun != FR_SUCC)
    {
        FRLOG_WARN_DETAIL("check [%s] err", p_so_name);
        goto ERROR;
    }
    
    //检查该so是否存在
    pthread_rwlock_wrlock(&rwlock);
    p_st_node = frlist_find(g_p_st_hdr_mng_module_use, &st_l7_module_tmp, __list_node_mng_find_l7_proto);
    if(p_st_node == NULL)
    {
        p_st_module_mng = frmalloc(sizeof(Frmodule_mng));
        if(p_st_module_mng == NULL)
        {
            pthread_rwlock_unlock(&rwlock);
            FRLOG_ERROR_DETAIL("frmalloc err");
            goto ERROR;
        }
        memset(p_st_module_mng, '\0', sizeof(Frmodule_mng));
        p_st_node = frlist_node_create(p_st_module_mng);
        if(p_st_node == NULL)
        {
            pthread_rwlock_unlock(&rwlock);
            FRLOG_ERROR_DETAIL("frlist_node_create err");
            frfree(p_st_module_mng);
            goto ERROR;
        }

        __frmodule_clone_l7_module(&p_st_module_mng->st_l7_module, &st_l7_module_tmp);
        p_st_module_mng->st_l7_module.ul_refcnt = 0L;
        p_st_module_mng->i_is_stub = FR_NO;
        p_st_module_mng->i_is_autocheck = i_is_autocheck;
        p_st_module_mng->p_so_name = frstrdup(p_so_name);
        p_st_module_mng->p_so_handle = p_so_handle;
        
        //模块初始化
        p_st_module_mng->st_l7_module.init(p_st_module_mng->st_l7_module.i_l7_proto
                                        , p_st_module_mng->st_l7_module.p_module_name
                                        , ui_mempool_max);

        frlist_push(g_p_st_hdr_mng_module_use, p_st_node);
        pthread_rwlock_unlock(&rwlock);
        FRLOG_INFO_DETAIL("load %s[%s] mempool size[%uM]ok", p_module_name, p_so_name, ui_mempool_max/1024/1024);

        return 0;
    }
    //更新老模块
    p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    i_is_stub = p_st_module_mng->i_is_stub;

    memcpy(&st_l7_module_old, &p_st_module_mng->st_l7_module, sizeof(L7_module));
    __frmodule_clone_l7_module(&p_st_module_mng->st_l7_module, &st_l7_module_tmp);
    p_st_module_mng->i_is_autocheck = i_is_autocheck;
    p_so_handle_old = p_st_module_mng->p_so_handle;
    p_st_module_mng->p_so_handle = p_so_handle;

    //模块初始化
    p_st_module_mng->st_l7_module.init(p_st_module_mng->st_l7_module.i_l7_proto
                                    , p_st_module_mng->st_l7_module.p_module_name
                                    , ui_mempool_max);
    FRLOG_INFO_DETAIL("load %s[%s] mempool size[%uM]ok", p_module_name, p_so_name, ui_mempool_max/1024/1024);

    pthread_rwlock_unlock(&rwlock);

    //释放老模块信息
    if(i_is_stub == FR_NO)
    {
        __frmodule_free_l7_module(&st_l7_module_old);

        if( p_so_handle_old != NULL)
            dlclose(p_so_handle_old);
    }
    FRLOG_INFO_DETAIL("load %s[%s] ok", p_module_name, p_so_name);
    return 0;

ERROR:
    //释放模块信息
    if(p_so_handle)
        dlclose(p_so_handle);

    return i_ret;
}

#endif

/*******************************************************************************
*  FUNC     :  卸载指定模块
*  ARGS     :  i_l7_proto      (全局使用的l7号)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  
*******************************************************************************/
int frmodule_unregister(int i_l7_proto)
{
    Frlist_node *p_st_node=NULL;
    Frmodule_mng *p_st_module_mng = NULL, *p_mng_module_del=NULL;
    L7_module st_l7_module_tmp;
    
    if(g_p_st_hdr_mng_module_use == NULL || g_p_st_hdr_mng_module_del==NULL)
        return FR_FAIL;
    
    memset(&st_l7_module_tmp, '\0', sizeof(L7_module));
    st_l7_module_tmp.i_l7_proto = i_l7_proto;
    
    pthread_rwlock_wrlock(&rwlock);
    
    //查询节点
    p_st_node = frlist_find(g_p_st_hdr_mng_module_use, &st_l7_module_tmp, __list_node_mng_find_l7_proto);
    if(p_st_node == NULL)
    {
        pthread_rwlock_unlock(&rwlock);
        FRLOG_WARN_DETAIL("module not found, l7_proto=%d", i_l7_proto);
        return FR_FAIL;
    }
    p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_module_mng == NULL || p_st_module_mng->i_is_stub == FR_YES )
    {
        pthread_rwlock_unlock(&rwlock);
        FRLOG_INFO_DETAIL("module not exist, l7_proto=%d", i_l7_proto);
        return FR_FAIL;
    }
    
    //生成删除节点
    p_mng_module_del = frmalloc(sizeof(Frmodule_mng));
    if(p_mng_module_del == NULL )
    {
        pthread_rwlock_unlock(&rwlock);
        FRLOG_ERROR_DETAIL("frmalloc err");
        return FR_FAIL;
    }
    memcpy(p_mng_module_del, p_st_module_mng, sizeof(Frmodule_mng));
    p_mng_module_del->p_so_name = NULL;
    p_st_node = frlist_node_create(p_mng_module_del);
    if(p_st_node == NULL)
    {
        pthread_rwlock_unlock(&rwlock);
        FRLOG_ERROR_DETAIL("frmalloc err");
        frfree(p_mng_module_del);
        return FR_FAIL;
    }
    frlist_push(g_p_st_hdr_mng_module_del, p_st_node);
    
    //设置老节点为stub
    p_st_module_mng->i_is_stub = FR_YES;
    frl7module_stub(&p_st_module_mng->st_l7_module);
    p_st_module_mng->p_so_handle = NULL;
    
    pthread_rwlock_unlock(&rwlock);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  节点检查，并删除
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_data          (void *)
*  RTN      :
*  NOTE     : 0:pf_run控制退出; 1:运行到最后
*******************************************************************************/
static int __list_node_mng_chk_del(Frlist_node* p_st_node, const void *p_data)
{
    Frmodule_mng *p_st_module_mng = NULL;
    
    if(p_st_node==NULL || p_st_node->data == NULL )
        return 1;

    //获取节点下的管理模块
    p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_module_mng->st_l7_module.ul_refcnt > 0)
        return 1;
    
    frlist_node_free(g_p_st_hdr_mng_module_del, p_st_node, 1, __list_node_mng_free);
    return 1;
}

/*******************************************************************************
*  FUNC     :  按模块名释放
*  ARGS     :  i_l7_proto   (全局使用的l7代号)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  
*******************************************************************************/
static int __frmodule_del_no_ref(void)
{
    if(g_p_st_hdr_mng_module_del == NULL)
        return FR_FAIL;
    
    pthread_rwlock_wrlock(&rwlock);
    frlist_run(g_p_st_hdr_mng_module_del, NULL, __list_node_mng_chk_del);
    pthread_rwlock_unlock(&rwlock);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  检查并删除不用模块
*  ARGS     :
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
static void *__frmodule_chk_module(void *arg)
{
    int i_loop =0;
    while(g_i_flag_run)
    {
        __frmodule_del_no_ref();
        
        for(i_loop =0;g_i_flag_run && i_loop < APM_MNG_MODULE_CHK_TIME; i_loop++)
            sleep(1);
    }
    pthread_exit(0);
    
    return (void*)NULL;
}

/*******************************************************************************
*  FUNC     :  按协议(tcp/udp),获取检查链表
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_data          (void *)
*  RTN      :
*  NOTE     : 0:pf_run控制退出; 1:运行到最后
*******************************************************************************/
static int __list_node_mng_mk_chklist(Frlist_node *p_st_node_in, const void *p_data)
{
    Frlist_node *p_st_node;
    Frchk_module_mng *p_st_chk_module=NULL;
    Frmodule_mng *p_st_module_mng=NULL;
    L7_module  *p_st_l7_module=NULL;
    
    if(p_st_node_in==NULL || p_st_node_in->data == NULL || p_data == NULL)
        return 1;

    p_st_chk_module = (Frchk_module_mng *)p_data;
    //获取节点下的管理模块
    p_st_module_mng = (Frmodule_mng *)FRLIST_GET_NODE_DATA(p_st_node_in);
    if(p_st_module_mng->i_is_stub == FR_YES )
        return 1;
    
    //比较 协议(tcp/udp)和端口
    p_st_l7_module = &p_st_module_mng->st_l7_module;
    if( (p_st_l7_module->us_l4_proto & p_st_chk_module->i_ip_proto) == 0 )
        return 1;
    
    //协议自动判定
    if(p_st_module_mng->i_is_autocheck != p_st_chk_module->i_is_autocheck)
        return 1;

    //增加到查询链表
    p_st_node = frlist_node_create(p_st_module_mng);
    if(p_st_node == NULL)
        return 1;
    
    frlist_push(p_st_chk_module->p_lst_hdr, p_st_node);
    return 1;
}

/*******************************************************************************
*  FUNC     :  获取协议判断模块链表
*  ARGS     :  i_ip_proto      ( 6(IPPROTO_TCP)  / 17(IPPROTO_UDP) )
*           :  p_lst_hdr       ( 需要检查的协议保存在该链表 )
*           :  i_is_autocheck  (FR_YES:协议自动判定模块;FR_NO:协议不自动判定模块)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  
*******************************************************************************/
int frmodule_get_chklist(int i_ip_proto, Frlist_header *p_lst_hdr, int i_is_autocheck)
{
    Frchk_module_mng st_chk_module;
    
    if(p_lst_hdr == NULL ) 
        return FR_FAIL;
    st_chk_module.p_lst_hdr = p_lst_hdr;
    st_chk_module.i_ip_proto = i_ip_proto;
    st_chk_module.i_is_autocheck = i_is_autocheck;
    
    pthread_rwlock_rdlock(&rwlock);
    frlist_run(g_p_st_hdr_mng_module_use, &st_chk_module, __list_node_mng_mk_chklist);
    pthread_rwlock_unlock(&rwlock);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  获取协议模块
*  ARGS     :  i_l7_proto      (全局使用的l7代号 )
*  RTN      :  Frmodule_mng*
*  NOTE     :  
*******************************************************************************/
Frmodule_mng *frmodule_get_module(int i_l7_proto)
{
    Frlist_node *p_st_node=NULL;
    Frmodule_mng *p_st_module_mng=NULL;
    L7_module st_l7_module;
    
    st_l7_module.i_l7_proto = i_l7_proto;
    
    pthread_rwlock_rdlock(&rwlock);
    p_st_node = frlist_find(g_p_st_hdr_mng_module_use, &st_l7_module, __list_node_mng_find_l7_proto);
    if(p_st_node == NULL || p_st_node->data == NULL)
    {
        pthread_rwlock_unlock(&rwlock);
        return NULL;
    }
    
    p_st_module_mng = (Frmodule_mng*)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_module_mng->i_is_stub == FR_YES )
    {
        pthread_rwlock_unlock(&rwlock);
        FRLOG_WARN_DETAIL("module [%s] is stub", p_st_module_mng->p_so_name);
        return NULL;
    }
    pthread_rwlock_unlock(&rwlock);
    
    return p_st_module_mng;
}

/*******************************************************************************
*  FUNC     :  管理模块内容出力
*  ARGS     :  p_st_hdr    (管理模块链表头指针)
*           :  p_title     (出力抬头)
*           :  pp_result   (出力结果)
*  RTN      : 
*  NOTE     :  1.注意如果传入pp_result,需要在外部释放内存
*           :  2.有长度限制
*******************************************************************************/
static void __frmodule_mng_output(Frlist_header *p_st_hdr, char *p_title, char **pp_result)
{
    char *p_outbuff=NULL;
    int i_outbuff_size =1024000, i_used=0;

    if(p_st_hdr == NULL)
        return;

    p_outbuff = frmalloc(i_outbuff_size);
    if(p_outbuff==NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        return;
    }

    snprintf(p_outbuff, i_outbuff_size, "regist module\n");
    i_used = strlen(p_outbuff);
    i_outbuff_size -= i_used;
    
    pthread_rwlock_rdlock(&rwlock);
    frlist_show(p_st_hdr, p_outbuff+i_used, i_outbuff_size, frmodule_mng_list_node_mng_show);
    pthread_rwlock_unlock(&rwlock);
    if(pp_result == NULL)
    {
        frdbg("==========================\n");
        printf("output %s data\n%s\n", p_title, p_outbuff);
        frdbg("==========================\n");
        frfree(p_outbuff);
    }
    else
        *pp_result = p_outbuff;

    return;
}

/*******************************************************************************
*  FUNC     :  管理模块内容出力
*  ARGS     :  pp_result   (出力结果)
*  RTN      : 
*  NOTE     :  1.注意如果传入pp_result,需要在外部释放内存
*           :  2.有长度限制
*******************************************************************************/
void frmodule_mng_output(char **pp_result)
{
    if(g_p_st_hdr_mng_module_use == NULL)
        return;
    
    __frmodule_mng_output(g_p_st_hdr_mng_module_use, "regist module", pp_result);

    return;
}

/*******************************************************************************
*  FUNC     :  模块管理初始化
*  ARGS     :
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frmodule_mng_init(void)
{
    int i_ret_fun;
    
    g_p_st_hdr_mng_module_use = frlist_create();
    if(g_p_st_hdr_mng_module_use == NULL)
        return FR_FAIL;

    g_p_st_hdr_mng_module_del = frlist_create();
    if(g_p_st_hdr_mng_module_del == NULL)
    {
        frfree(g_p_st_hdr_mng_module_use);
        return FR_FAIL;
    }

    i_ret_fun = pthread_create(&g_thread_id_chk, NULL, __frmodule_chk_module, NULL);
    if(i_ret_fun)
    {
        FRLOG_ERROR_DETAIL("pthread_create err");
        g_thread_id_chk = 0L;
        frfree(g_p_st_hdr_mng_module_del);
        frfree(g_p_st_hdr_mng_module_use);
        return FR_FAIL;
    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  获取 协议so:l7协议号:协议名
*  ARGS     :  p_token_lib      (解析用字符串)
*           :  pp_lib_name      (协议so)
*           :  p_ip_proto       (l4协议号)
*           :  pp_lib_l7_proto  (l7协议号)
*           :  pp_lib_module_name(协议名)
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  函数内部没有分配内存,没有内存释放的问题
*******************************************************************************/
static int __frmodule_cfg_get_param(char *p_token_lib
                                     , char **pp_lib_name
                                     , u_short *p_ip_proto
                                     , char **pp_lib_l7_proto
                                     , char **pp_lib_module_name
                                     , unsigned int *p_ui_mempool_max
                                     , int *p_i_is_autocheck)
{
    char *p_temp=NULL;
    if(p_token_lib == NULL || *p_token_lib == '\0'
       || pp_lib_name == NULL || p_ip_proto==NULL || pp_lib_l7_proto==NULL || pp_lib_module_name==NULL
       || p_ui_mempool_max == NULL)
        return FR_FAIL;

    //取协议so
    *pp_lib_name = strsep(&p_token_lib,":");
    if(*pp_lib_name == NULL || **pp_lib_name == '\0')
        return FR_FAIL;

    //l4协议号
    if(p_token_lib == NULL)
        return FR_FAIL;
    p_temp = strsep(&p_token_lib,":");
    if(p_temp == NULL || *p_temp == '\0')
        return FR_FAIL;
    if(strcasecmp("tcp", p_temp) == 0)
        *p_ip_proto = IPPROTO_TCP;
    else if(strcasecmp("udp", p_temp) == 0)
        *p_ip_proto = IPPROTO_UDP;
    else if(strcasecmp("any", p_temp) == 0)
        *p_ip_proto = IPPROTO_TCP | IPPROTO_UDP;
    else
        return FR_FAIL;

    //l7协议号
    if(p_token_lib == NULL)
        return FR_FAIL;
    *pp_lib_l7_proto = strsep(&p_token_lib,":");
    if(*pp_lib_l7_proto == NULL || **pp_lib_l7_proto == '\0')
        return FR_FAIL;

    //取协议名
    if(p_token_lib == NULL)
        return FR_FAIL;
    *pp_lib_module_name = strsep(&p_token_lib,":");
    if(*pp_lib_module_name == NULL || **pp_lib_module_name == '\0')
        return FR_FAIL;

    //取缓存池大小
    if(p_token_lib == NULL)
        return FR_FAIL;

    p_temp = strsep(&p_token_lib,":");
    if( p_temp == NULL || *p_temp == '\0')
        return FR_FAIL;

    *p_ui_mempool_max = atoi(p_temp);
    *p_ui_mempool_max = *p_ui_mempool_max * 1024 * 1024;//M转换为byte
    if(*p_ui_mempool_max < APM_ANALYZER_LIB_MEMPOOL_MIN)
    {
        *p_ui_mempool_max = APM_ANALYZER_LIB_MEMPOOL_MIN;
        FRLOG_WARN_DETAIL("[%s] set mempool size %uM", *pp_lib_name, APM_ANALYZER_LIB_MEMPOOL_MIN/1024/1024);
    }

    //协议自动判定标识
    if(p_token_lib == NULL)
        return FR_FAIL;
    p_temp = strsep(&p_token_lib,":");
    if( p_temp == NULL || *p_temp == '\0')
        return FR_FAIL;
    if( atoi(p_temp) == 0)
        *p_i_is_autocheck = FR_NO;
    else
        *p_i_is_autocheck = FR_YES;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  从配置文件中读取解析库配置
*  ARGS     :  i_run_unload         (FR_YES:加载libs_load,卸载libs_unload; FR_NO:只加载libs_load,一般程序启动时使用FR_NO)
*  RTN      :  FR_SUCC / FR_FAIL
*  NOTE     :  1. 如果增加配置，运行中更新配置文件没有问题
*           :  2. 如果有减少配置，请重新启动应用程序进行加载
*******************************************************************************/
#if !defined(FRDBG_MODULE_DEBUG)
int frmodule_cfg_load(int i_run_unload)
{
    int i_ret_fun=0;
    char *p_libs=NULL, *p_token_lib=NULL;
    char *p_lib_name=NULL, *p_lib_l7_proto=NULL, *p_lib_module_name=NULL;
    int i_is_autocheck=0;
    u_short us_ip_proto=0;
    unsigned int ui_mempool_max;
    char arr_one_lib[256];
    int i_l7_proto=0;

    //加载协议库
    i_ret_fun = frconfig_get_string(APM_CFG_FILENAME_ANALYZER, APM_ANALYZER_KEY_MODULE_LOAD, &p_libs);
    if(i_ret_fun != APM_FRCONFIG_SUCC || p_libs == NULL)
    {
        FRLOG_ERROR_DETAIL("open cfg[%s][%s] err", APM_CFG_FILENAME_ANALYZER, APM_ANALYZER_KEY_MODULE_LOAD);
        return FR_FAIL;
    }

    p_token_lib = strtok(p_libs,";");
    while(p_token_lib != NULL)
    {
        //获取so, l7_proto, module_name
        p_lib_name=NULL;
        p_lib_l7_proto=NULL;
        p_lib_module_name=NULL;
        i_is_autocheck = FR_NO;
        snprintf(arr_one_lib, sizeof(arr_one_lib), "%s", p_token_lib);
        i_ret_fun = __frmodule_cfg_get_param(p_token_lib, &p_lib_name, &us_ip_proto, &p_lib_l7_proto, &p_lib_module_name, &ui_mempool_max, &i_is_autocheck);
        if(i_ret_fun== FR_FAIL)
        {
            FRLOG_WARN_DETAIL("config [%s] err", arr_one_lib);
            //取下一个协议解析库
            p_token_lib = strtok(NULL,";");
            continue;
        }
        frdbg("[%s]:[%s][%s][%s][%s][%s]\n", arr_one_lib, p_lib_name, FR_L4PROTO2STR(us_ip_proto), p_lib_l7_proto, p_lib_module_name, FR_YESNO2STR(i_is_autocheck));

        i_l7_proto=atoi(p_lib_l7_proto);
        i_ret_fun = frmodule_register(p_lib_name, i_is_autocheck, us_ip_proto, i_l7_proto, p_lib_module_name, ui_mempool_max);
        if(i_ret_fun == 1)
        {
            //FRLOG_WARN_DETAIL("load [%s] l7_proto=%d module_name[%s] err", p_lib_name, i_l7_proto, p_lib_module_name);
            //取下一个协议解析库
            p_token_lib = strtok(NULL,";");
            continue;
        }
        FRLOG_INFO_DETAIL("load [%s] l7_proto=%d module_name[%s] ok", p_lib_name, i_l7_proto, p_lib_module_name);

        //取下一个协议解析库
        p_token_lib = strtok(NULL,";");
    }
    if(p_libs)
        frfree(p_libs);

    //卸载协议库
    if(i_run_unload == FR_NO)
        return FR_SUCC;

    i_ret_fun = frconfig_get_string(APM_CFG_FILENAME_ANALYZER, APM_ANALYZER_KEY_MODULE_UNLOAD, &p_libs);
    if(i_ret_fun != APM_FRCONFIG_SUCC || p_libs == NULL)
    {
        FRLOG_INFO_DETAIL("open cfg[%s][%s], no config data", APM_CFG_FILENAME_ANALYZER, APM_ANALYZER_KEY_MODULE_UNLOAD);
        return FR_SUCC;
    }
    p_token_lib = strtok(p_libs,";");
    while(p_token_lib != NULL)
    {
        if( *p_token_lib == '\0' )
        {
            p_token_lib = strtok(NULL,";");
            continue;
        }

        i_l7_proto=atoi(p_token_lib);
        i_ret_fun = frmodule_unregister(i_l7_proto);
        if(i_ret_fun == FR_SUCC)
            FRLOG_INFO_DETAIL("unload [%d] ok", i_l7_proto);
        else
            FRLOG_INFO_DETAIL("unload [%d] fail", i_l7_proto);
        p_token_lib = strtok(NULL,";");
    }
    if(p_libs)
        frfree(p_libs);
    return FR_SUCC;
}
#endif

/*******************************************************************************
*  FUNC     :  模块管理资源释放
*  ARGS     :  
*  RTN      :  
*  NOTE     :
*******************************************************************************/
void frmodule_mng_destory(void)
{
    if(g_thread_id_chk)
        pthread_join(g_thread_id_chk, NULL);

    if(g_p_st_hdr_mng_module_del)
    {
        frlist_destroy(g_p_st_hdr_mng_module_del, __list_node_mng_free);
        g_p_st_hdr_mng_module_del = NULL;
    }

    if(g_p_st_hdr_mng_module_use)
    {
        frlist_destroy(g_p_st_hdr_mng_module_use, __list_node_mng_free);
        g_p_st_hdr_mng_module_use = NULL;
    }

    return;
}
